/*---------------------------------------------------------------------
File        : Error.cls
Purpose     :

Syntax      :

Description :

Author(s)   : Unknown
Created     : generated 11/12/08
Notes       :
    License     :
    This file is part of the QRX-SRV-OE software framework.
    Copyright (C) 2011, SC Yonder SRL (http://www.tss-yonder.com)

    The QRX-SRV-OE software framework is free software; you can redistribute
    it and/or modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either version 2.1
    of the License, or (at your option) any later version.

    The QRX-SRV-OE software framework is distributed in the hope that it will
    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
    General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with the QRX-SRV-OE software framework; if not, write to the Free
    Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301  USA or on the internet at the following address:
    http://www.gnu.org/licenses/lgpl-2.1.txt
---------------------------------------------------------------------*/
routine-level on error undo, throw.

&scoped-define err-config-section  'ErrorService':u
using com.quarix.service.error.ErrorCore.

class com.quarix.service.error.ErrorCore
    inherits com.quarix.service.error.ErrorBase
    implements com.quarix.base.iSingleton use-widget-pool:

    {com/quarix/service/error/ttError.i &scope=private}

    /*roxanam */
    define private query qryErr for ttError scrolling.

   &if keyword-all('static':u) ne ? &then
    define private static variable errorCore as ErrorCore no-undo.

    constructor public ErrorCore():
    end constructor.

    method public static ErrorCore GetInstance():
        if not valid-object(errorCore) then
            errorCore = new ErrorCore().
        return errorCore.
    end method.
   &else
    constructor public ErrorCore():
        do on error undo, return error:
            run com/quarix/base/enforceSingleton.p (this-object).
        end.
        LogLevel = InfoLevel().
    end constructor.
   &endif

    method public override void UpdateErrorNum ():
        define buffer bttError for ttError.
        assign
            NumMessages          = 0
            NumErrors            = 0
            NumWarnings          = 0
            NumInfos             = 0
            NumDebugMessages     = 0
            NumApplicationErrors = 0
            NumClientErrors      = 0.
        for each bttError no-lock:
            if bttError.errorLevel = ApplicationLevel() then
            do:
                NumMessages          = NumMessages + 1.
                NumApplicationErrors = NumApplicationErrors + 1.
            end.
            if bttError.errorLevel = DebugLevel() then
            do:
                NumDebugMessages = NumDebugMessages + 1.
            end.
            if bttError.errorLevel = ErrorLevel() then
            do:
                NumMessages = NumMessages + 1.
                NumErrors   = NumErrors + 1.
            end.
            if bttError.errorLevel = ClientLevel () then
            do:
                NumMessages     = NumMessages + 1.
                NumClientErrors = NumClientErrors + 1.
            end.
            if bttError.errorLevel = InfoLevel () then
            do:
                NumMessages = NumMessages + 1.
                NumInfos    = NumInfos + 1.
            end.
            if bttError.errorLevel = WarningLevel () then
            do:
                NumMessages = NumMessages + 1.
                NumWarnings = NumWarnings + 1.
            end.
        end.

    end method.

    method public override void Purge ():
        define buffer ttError for ttError.

        empty temp-table ttError.
        assign
            NumMessages          = 0
            NumErrors            = 0
            NumWarnings          = 0
            NumInfos             = 0
            NumDebugMessages     = 0
            NumApplicationErrors = 0
            NumClientErrors      = 0.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
        end catch.
    end method.

    method public override void Purge (input errorLevel as integer, input errorObject as character):
        define buffer ttError for ttError.

        if errorObject = '' then
            errorObject = ?.

        for each ttError
            where (errorLevel  eq ? or ttError.errorLevel  ge errorLevel)
            and (errorObject eq ? or ttError.errorObject eq errorObject)
            on error undo, throw:
            case ttError.errorLevel:
                when ErrorLevel() then
                    NumErrors   = NumErrors - 1.
                when WarningLevel()  then
                    NumWarnings = NumWarnings - 1.
                when InfoLevel()  then
                    NumInfos    = NumInfos - 1.
                when ApplicationLevel()   then
                    NumApplicationErrors = NumApplicationErrors - 1.
            end case.
            if ttError.errorLevel ne DebugLevel() then
                NumMessages = NumMessages - 1.
            delete ttError.
        end.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
        end catch.
    end method.

    method public override void Log
        (input logService  as com.quarix.service.logging.iLogger,
        input errorLevel  as integer,
        input errorObject as character):
        define buffer ttError for ttError.

        define variable lCustom as logical no-undo.

        if errorObject = '' then
            errorObject = ?.

        if valid-object(logService) and logService:OpenLog() then
        do:
            lCustom = type-of(logService,'com.quarix.service.logging.JsonLogger').

            if errorLevel eq ApplicationLevel() then
                for each ttError
                    where ttError.errorLevel  eq errorLevel
                    and (errorObject eq ? or ttError.errorObject eq errorObject)
                    on error undo, throw:
                    if not lCustom then
                        logService:LogError(if Util:IsEmpty(ttError.errorType) then ttError.errorLevel else ttError.errorType,   ttError.errorCode,
                            ttError.errorMessage, ttError.errorParam,
                            ttError.errorObject,  ttError.logTime).
                    else
                        logService:LogError(if Util:IsEmpty(ttError.errorType) then ttError.errorLevel else ttError.errorType,   ttError.errorCode,
                            ttError.errorMessage, ttError.errorParam,
                            ttError.errorObject,  ttError.logTime, ttError.errorRecord, ttError.errorTag).
                end.
            else
                for each ttError
                    where (errorLevel  eq ? or ttError.errorLevel  le errorLevel)
                    and (errorObject eq ? or ttError.errorObject eq errorObject)
                    on error undo, throw:
                    /*roxanam : log error with the new and old template*/
                    if (errorObject eq ? and (not Util:IsEmpty(ttError.errorMethod))) then
                        logService:LogError(ttError.errorLevel, ttError.errorCode, ttError.errorMessage,
                            ttError.errorFile, ttError.errorMethod, ttError.errorLine, ttError.logTime).
                    else
                    do:
                        if not lCustom then
                            logService:LogError(if Util:IsEmpty(ttError.errorType) then ttError.errorLevel else ttError.errorType,   ttError.errorCode,
                                ttError.errorMessage, ttError.errorParam,
                                ttError.errorObject,  ttError.logTime).
                        else
                            logService:LogError(if Util:IsEmpty(ttError.errorType) then ttError.errorLevel else ttError.errorType,   ttError.errorCode,
                                ttError.errorMessage, ttError.errorParam,
                                ttError.errorObject,  ttError.logTime, ttError.errorRecord, ttError.errorTag).
                    end.
                end.
            logService:CloseLog().
        end.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
        end catch.
    end method.

    method protected override logical ErrorRegister (input errorLevel as integer, input errorType as integer, input errorCode as integer, input errorText as character, input errorParam as character, input errorObject as character, input errorRecord as integer, input errorTag as character):
        define buffer ttError for ttError.

        if errorLevel ne ?
            and errorCode ne ?
            and (LogLevel = 0 or errorLevel le LogLevel or errorLevel eq ApplicationLevel()) then
        do:
            create ttError.
            assign
                ttError.logTime      = DtUtilManager:sysNow()
                ttError.errorLevel   = errorLevel
                ttError.errorType    = errorType
                ttError.errorCode    = errorCode
                ttError.errorMessage = errorText
                ttError.errorParam   = errorParam
                ttError.errorObject  = errorObject
                ttError.errorRecord  = errorRecord
                ttError.errorTag     = errorTag
                .
            return true.
        end.
        return false.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
            return false.
        end catch.
    end method.

    method protected override logical ErrorRegister (input errorLevel as integer, input errorType as integer, input errorCode as integer, input errorText as character, input errorParam as character, input errorObject as character, input errorRecord as integer):
        return ErrorRegister (errorLevel, errorType, errorCode, errorText, errorParam, errorObject, errorRecord, ?).
    end method.

    method protected override logical ErrorRegister (input errorLevel as integer, input errorType as integer, input errorCode as integer, input errorText as character, input errorParam as character, input errorObject as character):
        return ErrorRegister (errorLevel, errorType, errorCode, errorText, errorParam, errorObject, ?).
    end method.

    method protected override logical ErrorRegister (input errorLevel as integer, input errorCode as integer, input errorText as character, input errorParam as character, input errorObject as character):
        return ErrorRegister (errorLevel, ?, errorCode, errorText, errorParam, errorObject).
    end method.

    /*roxanam: add error information to temp-table (get information from callstack can be proccessed here)*/
    method protected override logical ErrorRegister (input errorLevel as integer, input errorCode as integer, input errorText as character, input errorFile as character, input errorMethod as character, input errorLine as integer):

        define buffer ttError for ttError.

        if errorLevel ne ?
            and errorCode ne ?
            and (LogLevel = 0 or errorLevel le LogLevel or errorLevel eq ApplicationLevel()) then
        do:
            create ttError.
            assign
                ttError.logTime      = DtUtilManager:sysNow()
                ttError.errorLevel   = errorLevel
                ttError.errorCode    = errorCode
                ttError.errorMessage = errorText
                ttError.errorFile    = errorFile
                ttError.errorMethod  = errorMethod
                ttError.errorLine    = errorLine
                .
            return true.
        end.
        return false.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
            return false.
        end catch.
    end method.

    method override public character GetError (input errorIndex as integer, input errorLevel as integer, errorObject as character):
        define variable errMsg as character no-undo initial ?.

        if openQuery(errorLevel, errorObject) then
        do:
            if errorIndex gt 1 then
                query qryErr:reposition-to-row(errorIndex).
            query qryErr:get-next().
            if available(ttError) then
            do:
                /*roxanam - get error in the old and new fashion*/
                if (errorObject eq ? and (not Util:IsEmpty(ttError.errorMethod))) then
                    errMsg = substitute('&1,&2,&3,&4,&5':u, ttError.errorCode, ttError.errorMessage, ttError.errorFile, ttError.errorMethod, ttError.errorLine).
                else
                    errMsg = substitute('&1,&2,&3,&4':u, ttError.errorCode, ttError.errorMessage, ttError.errorObject, ttError.errorParam).
            end.
            query qryErr:query-close().
        end.
        return errMsg.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
            return ?.
        end catch.
    end method.

    method override public integer GetNumObjectErrors (input errorLevel as integer, errorObject as character):
        define variable numErr as integer no-undo.

        if openQuery(errorLevel, errorObject) then
        do:
            numErr = query qryErr:num-results.
            query qryErr:query-close().
        end.
        return numErr.

        catch appError as Progress.Lang.Error :
            ThrowError(input appError).
            delete object appError.
            return ?.
        end catch.
    end method.

    method public void Reset ():
        if valid-object(Application) then
            LogLevel = Application:LogLevel.
    end method.

    method private logical openQuery (input errorLevel as integer, errorObject as character):
        if errorLevel eq ? then
        do:
            if errorObject eq ? then
                query qryErr:query-prepare('preselect each ttError':u).
            else
                query qryErr:query-prepare(substitute('preselect each ttError where errorObject eq &1':u, quoter(errorObject))).
        end.
        else
        do:
            if errorObject eq ? then
                query qryErr:query-prepare(substitute('preselect each ttError where errorLevel eq &1':u, quoter(errorLevel))).
            else
                query qryErr:query-prepare(substitute('preselect each ttError where errorLevel eq &1 and errorObject eq &2':u,
                    quoter(errorLevel), quoter(errorObject))).
        end.
        query qryErr:query-open().
        return true.
    end method.

    method public override handle GetTmpErrorHandle():

        return buffer ttError:table-handle.

    end method.

    method public override void DumpToXml():

        define variable cLogDirectory    as character	no-undo.
        define variable cLogFileName     as character	no-undo.
        define variable cFullLogFileName	as character	no-undo.
        define variable iNum             as integer   no-undo.
        define variable cFileName        as character	no-undo.
        define variable httHandle        as handle    no-undo.

        httHandle = buffer ttError:handle.

        assign
            cLogDirectory	= Util:GetLogDirectory()
            cFileName     = httHandle:name.

        if cFileName = '' or
            cFileName = ? or
            cLogDirectory = '' or
            cLogDirectory = ?
            then return.

        assign
            cLogFileName     = cFileName + '.xml':U
            cFullLogFileName	= cLogDirectory + '~/':U + cLogFileName.

        do while search(cFullLogFileName) <> ?:

            iNum = iNum + 1.

            assign
                cLogFileName     = cFileName + '_':U + string(iNum) + '.xml':U
                cFullLogFileName	= cLogDirectory + '~/':U + cLogFileName.

        end. /* do while search(cFullLogFileName) = ? */

        httHandle:write-xml('file':U, cFullLogFileName, yes).

        return.

        catch appError as Progress.Lang.Error :
            delete object appError.
        end catch.

    end method.

end class.


